package org.springblade.modules.digitalization.manager;


import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.LogConstant;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.oss.ArchiveMinioTemplate;
import org.springblade.core.oss.model.OssFile;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.digitalization.contant.ConstantDigit;
import org.springblade.modules.digitalization.dto.DataExchangeDTO;
import org.springblade.modules.digitalization.entity.A01Entity;
import org.springblade.modules.digitalization.entity.UmsUserInfoEntity;
import org.springblade.modules.digitalization.service.IA01Service;
import org.springblade.modules.digitalization.service.IUmsUserInfoService;
import org.springblade.modules.digitalization.vo.CheckResultVo;
import org.springblade.modules.digitalization.vo.DataExchangeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Service
public class DataExchangeManager {


	@Autowired
	private RedisTemplate<String, String> redisTemplate;


	@Autowired
	private IUmsUserInfoService umsUserInfoService;

	@Autowired
	private IA01Service a01Service;

	@Autowired
	private LogManager logManager;

	// 任务列表
	private final String TASK_LIST_KEY = "data-exchange:tasks";

	// 数据
	private final String DATA_KEY = "data-exchange:data:";

	@Autowired
	private ArchiveMinioTemplate minioTemplate;


	@PostConstruct
	public void start() {
		new Thread(() -> {
			while (true) {
				try {
					doTask();
				} catch (Exception e) {
					log.error("转换任务执行异常", e);
				}
			}
		}).start();
	}


	private void doTask() {
		ListOperations<String, String> opsForList = redisTemplate.opsForList();
		String a0000 = opsForList.leftPop(getCacheName(TASK_LIST_KEY), 10, TimeUnit.SECONDS);
		if (StringUtil.isBlank(a0000)) {
			return;
		}
		log.info("获取到转换任务，档案ID： {}", a0000);
		String dataKey = getDataKey(a0000);
		if (redisTemplate.hasKey(dataKey)) {
			DataExchangeVO data = JSON.parseObject(redisTemplate.opsForValue().get(dataKey), DataExchangeVO.class);
			log.info("开始处理任务");
			try {
				umsUserInfoService.doExchangeTask(data, data.getEnableHd(), new DataExchangeCallback() {
					@Override
					public void handleUpdate(DataExchangeVO dataExchangeVO) {
						redisTemplate.opsForValue().set(getDataKey(dataExchangeVO.getA0000()), JSON.toJSONString(dataExchangeVO));
					}

					@Override
					public void setTaskCount(int count) {
						data.setTaskCount(count);
						this.handleUpdate(data);
					}

					@Override
					public void addSuccessCount(int count) {
						data.setSuccessCount(data.getSuccessCount() + count);
						this.handleUpdate(data);
					}
				});

			} catch (Exception e) {
				data.setMessage(StringUtil.trimWhitespace(data.getMessage() + "\n" + e.getMessage()));
				data.setStatus(ConstantDigit.DATA_EXCHANGE_STATUS_ERROR);
				redisTemplate.opsForValue().set(getDataKey(data.getA0000()), JSON.toJSONString(data));
			}
		} else {
			log.info("任务已取消，档案ID：{}", a0000);
		}
	}


	public void addData(DataExchangeDTO dataExchangeDTO) {

		ListOperations<String, String> opsForList = redisTemplate.opsForList();

		List<DataExchangeVO> taskDatas = getTaskDatas(dataExchangeDTO.getA0000List(), dataExchangeDTO.getA0201b());

		taskDatas.forEach(dataExchangeVO -> {
			// 先判断任务是否存在，如果存在，就不添加
			if (redisTemplate.hasKey(getDataKey(dataExchangeVO.getA0000()))) {
				return;
			}
			dataExchangeVO.setEnableHd(dataExchangeDTO.getEnableHd());
			dataExchangeVO.setIsOfd(dataExchangeDTO.getIsOfd());
			dataExchangeVO.setIsZip(dataExchangeDTO.getIsZip());
			dataExchangeVO.setDipUnit(dataExchangeDTO.getDipUnit());

			// 存储数据
			redisTemplate.opsForValue().set(getDataKey(dataExchangeVO.getA0000()), JSON.toJSONString(dataExchangeVO));
			// 添加任务
			opsForList.rightPush(getTaskKey(), dataExchangeVO.getA0000());

			a01Service.getUserInfoByArchiveId(dataExchangeVO.getA0000());

			A01Entity oldData = a01Service.getByA0000(dataExchangeVO.getA0000());
			A01Entity newData = ObjectUtil.clone(oldData);
			newData.setStatus(ConstantDigit.A01_STATUS_FINISH);

			logManager.doBizUpdate(dataExchangeVO.getA0000(), LogManager.TYPE_A01, "数据交换", oldData, newData);
		});
	}

	private List<DataExchangeVO> getTaskDatas(List<String> a0000List, String a0201b) {
		List<A01Entity> a01Entities;
		if (StringUtil.isNotBlank(a0201b)) {
			a01Entities = a01Service.getByA0195AndStatus(a0201b, 6);
		} else {
			a01Entities = a01Service.getByA0000AndStatus(a0000List, 6);
		}
		List<DataExchangeVO> collect = a01Entities.stream().map(a01Entity -> {
			DataExchangeVO dataExchangeVO = new DataExchangeVO();
			dataExchangeVO.setStatus(ConstantDigit.DATA_EXCHANGE_STATUS_WAIT);
			dataExchangeVO.setCreateUser(AuthUtil.getUser().getNickName());
			dataExchangeVO.setCreateUserId(AuthUtil.getUser().getUserId());
			dataExchangeVO.setA0000(a01Entity.getA0000());
			dataExchangeVO.setA0101(a01Entity.getA0101());
			dataExchangeVO.setA0184(a01Entity.getA0184());
			dataExchangeVO.setZip(false);
			dataExchangeVO.setOfd(false);
			return dataExchangeVO;
		}).collect(Collectors.toList());
		long time = new Date().getTime();
		for (DataExchangeVO dataExchangeVO : collect) {
			dataExchangeVO.setCreateTime(new Date(time++));
		}
		return collect;
	}


	public List<DataExchangeVO> list(Long createdUserId) {
		Set<String> keys = redisTemplate.keys(DATA_KEY + "*");
		List<DataExchangeVO> collect = redisTemplate.opsForValue().multiGet(keys)
			.stream().filter(StringUtil::isNotBlank)
			.map(value -> JSON.parseObject(value, DataExchangeVO.class))
			.filter(dataExchangeVO -> {
				if (createdUserId == null) {
					return true;
				}
				return dataExchangeVO.getCreateUserId().equals(createdUserId);
			})
			.sorted(Comparator.comparing(DataExchangeVO::getCreateTime))
			.collect(Collectors.toList());
		return collect;
	}


	public void remove(String a0000) {
		String value = redisTemplate.opsForValue().get(getDataKey(a0000));
		if (StringUtil.isBlank(value)) {
			return;
		}
		DataExchangeVO dataExchangeVO = JSON.parseObject(value, DataExchangeVO.class);
		// 判断是否正在处理
		if (dataExchangeVO.getStatus().equals(ConstantDigit.DATA_EXCHANGE_STATUS_PROCESS)) {
			return;
		}
		redisTemplate.delete(getDataKey(a0000));
	}


	public void reAdd(String a0000) {
		String value = redisTemplate.opsForValue().get(getDataKey(a0000));
		if (StringUtil.isBlank(value)) {
			return;
		}
		DataExchangeVO dataExchangeVO = JSON.parseObject(value, DataExchangeVO.class);
		// 判断是否失败
		if (dataExchangeVO.getStatus().equals(ConstantDigit.DATA_EXCHANGE_STATUS_ERROR) == false) {
			return;
		}

		dataExchangeVO.setStatus(ConstantDigit.DATA_EXCHANGE_STATUS_WAIT);
		dataExchangeVO.setMessage("");
		dataExchangeVO.setTaskCount(0);
		dataExchangeVO.setSuccessCount(0);
		dataExchangeVO.setZip(false);
		dataExchangeVO.setOfd(false);

		// 存储数据
		redisTemplate.opsForValue().set(getDataKey(dataExchangeVO.getA0000()), JSON.toJSONString(dataExchangeVO));

		// 添加任务
		redisTemplate.opsForList().rightPush(getTaskKey(), a0000);
	}


	private String getTaskKey() {
		return getCacheName(TASK_LIST_KEY);
	}

	private String getDataKey(String a0000) {
		return getCacheName(DATA_KEY + a0000);
	}

	private String getCacheName(String key) {
		String data_exchange = CacheUtil.formatCacheName(key, false);
		return data_exchange;
	}

	public void removeFinished() {
		Set<String> allKey = redisTemplate.keys(DATA_KEY + "*");
		List<String> finishedKey = redisTemplate.opsForValue().multiGet(allKey)
			.stream().
			filter(StringUtil::isNotBlank)
			.map(value -> JSON.parseObject(value, DataExchangeVO.class))
			.filter(dataExchangeVO -> dataExchangeVO.getStatus().equals(ConstantDigit.DATA_EXCHANGE_STATUS_FINISH))
			.map(dataExchangeVO -> DATA_KEY + dataExchangeVO.getA0000())
			.collect(Collectors.toList());
		redisTemplate.delete(finishedKey);
	}


	public int checkDataExchange() {
		// 检查文件名
		// int stream
		int current = 1;
		int updateCount = 0;

		// 批量更新未完成转换的数据
		A01Entity baseUpdate = new A01Entity();
		baseUpdate.setIsOfd(false);
		baseUpdate.setIsZip(false);
		a01Service.update(baseUpdate, Wrappers.<A01Entity>lambdaQuery().le(A01Entity::getStatus, ConstantDigit.A01_STATUS_FINISH));

		while (true) {
			// 只查询已经完成的数据
			Page<A01Entity> page = a01Service.page(Page.of(current, 100), Wrappers.<A01Entity>lambdaQuery().eq(A01Entity::getStatus, ConstantDigit.A01_STATUS_FINISH));
			if (page.getRecords().isEmpty()) {
				break;
			}
			List<A01Entity> dataForUpdate = Lists.newArrayList();
			page.getRecords().forEach(a01Entity -> {
				boolean isZip = checkFile(a01Entity, "zip");
				boolean isOfd = checkFile(a01Entity, "ofd");
				A01Entity itemUpdate = new A01Entity();
				boolean update = false;

				if (isZip != a01Entity.getIsZip()) {
					itemUpdate.setIsZip(isZip);
					update = true;
				}

				if (isOfd != a01Entity.getIsOfd()) {
					itemUpdate.setIsOfd(isOfd);
					update = true;
				}

				if (update) {
					itemUpdate.setId(a01Entity.getId());
					itemUpdate.setA0101(a01Entity.getA0101());
					itemUpdate.setA0184(a01Entity.getA0184());
					dataForUpdate.add(itemUpdate);
				}
			});
			try {
				a01Service.updateBatchById(dataForUpdate);
				updateCount += dataForUpdate.size();

			} catch (Exception e) {
				log.error("更新失败", e);
			}
			current++;
		}

		return updateCount;
	}

	private boolean checkFile(A01Entity a01, String suffix) {
		String filePath = a01.getA0000() + "/" + a01.getA0101() + a01.getA0184() + "." + suffix;
		try {
			OssFile ossFile = minioTemplate.statFile(filePath);
			if (ossFile != null) {
				return true;
			}
		} catch (Exception e) {
			log.warn(e.getMessage(), e);
		}
		return false;
	}
}
